using System.Collections;
using System.Collections.Generic;
using TMPro;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class UpgMenuUIMgr : MonoBehaviour
{
    [Header("Settings")]
    public int _iptDur;
    /// <summary>
    /// For continuously ipt.
    /// </summary>
    private int _iptTimer;
    /// <summary>
    /// For continuously ipt.
    /// </summary>
    private bool _isUpg;
    /// <summary>
    /// For continuously ipt.
    /// </summary>
    private bool _isDwg;
    private int IptTimer { get => _iptTimer; set => _iptTimer = math.max(0, math.min(value, _iptDur)); }

    [Header("Components")]
    public TMP_Text _rscCnt;
    public Image[] _cursors;
    public GameObject _HP;
    private Image[] _HPs;
    public GameObject[] _skillCostFrameObj;
    public GameObject[] _skillCostContentObj;
    private Image[][] _skillCostFrame;
    private Image[][] _skillCostContent;
    public Image[] _skills;
    public Image[] _SPs;
    public Image[] _MPs;
    private Canvas _canvas;
    private FuncType _cursor;
    private int _horCursor;

    private PropModule _PM;
    private SkillModule _SM;

    [Header("Prop Buffer")]
    public int _restingRsc;
    private int _curMaxHP;
    private int _curSPSlot;
    private int _curMPSlot;

    public int RestingRsc { get => _restingRsc; set => _restingRsc = math.max(0, value); }
    private int CurMaxHPBuffer { get => _curMaxHP; set => _curMaxHP = math.max(0, value); }
    private int CurSPSlotBuffer { get => _curSPSlot; set => _curSPSlot = math.max(0, value); }
    private int CurMPSlotBuffer { get => _curMPSlot; set => _curMPSlot = math.max(0, value); }

    private bool[] _isLoaded;
    private bool[] _isEvled;
    public bool[] IsLoaded { get => _isLoaded; set => _isLoaded = value; }
    public bool[] IsEvled { get => _isEvled; set => _isEvled = value; }

    private void Start() { }

    private void Update()
    {
        ContinuouslyIpt();
    }

    #region Application interface
    public void IniDspl(PropModule UIPM, SkillModule UISM)
    {
        _canvas = GetComponent<Canvas>();
        _HPs = _HP.GetComponentsInChildren<Image>();
        _PM = UIPM;
        _SM = UISM;
        _skillCostFrame = new Image[4][];
        _skillCostContent = new Image[4][];
        for (int i = 0; i < 4; i++) _skillCostFrame[i] = _skillCostFrameObj[i].GetComponentsInChildren<Image>();
        for (int i = 0; i < 4; i++) _skillCostContent[i] = _skillCostContentObj[i].GetComponentsInChildren<Image>();
        IsLoaded = new bool[4];
        IsEvled = new bool[4];
    }

    public void Dspl() { _canvas.enabled = true; }
    public void Close() { _canvas.enabled = false; }

    public void RfrBufferProp()
    {
        _PM.SetBufferData(CurMaxHPBuffer, CurSPSlotBuffer, CurMPSlotBuffer);
        _SM.SetBufferData(IsLoaded, IsEvled);
    }

    public void Rfr()
    {
        CurMaxHPBuffer = _PM.CurMaxHP;
        CurSPSlotBuffer = _PM.CurSPSlot;
        CurMPSlotBuffer = _PM.CurMPSlot;
        for (int i = 0; i < IsLoaded.Length; i++) IsLoaded[i] = _SM.IsLoaded[i];
        for (int i = 0; i < IsEvled.Length; i++) IsEvled[i] = _SM.IsEvled[i];

        _cursor = 0;
        _horCursor = 0;
        IptTimer = 0;
        _isUpg = false;
        _isDwg = false;

        UpdCursor(_cursor);
        UpdRsc();
        UpdProp(FuncType.HP);
        UpdProp(FuncType.SP);
        UpdProp(FuncType.MP);
        UpdSkill();
    }
    #endregion
    #region Cursor section
    public void MoveCursorDown(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started) MoveCursor(true);
    }

    public void MoveCursorUp(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started) MoveCursor(false);
    }

    private void MoveCursor(bool isMoveDown)
    {
        if (isMoveDown) _cursor = _cursor == (FuncType)3 ? 0 : _cursor + 1;
        else _cursor = _cursor == 0 ? (FuncType)3 : _cursor - 1;
        UpdCursor(_cursor);
        if (_cursor == FuncType.Skill) _horCursor = 0;//reset skill cursor
    }

    private void UpdCursor(FuncType cursor)
    {
        for (int i = 0; i < _cursors.Length; i++)
        {
            _cursors[i].enabled = false;
        }
        _cursors[(int)cursor].enabled = true;
        IptTimer = 0;//new section
    }

    public void MoveCursorLeft(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started) MoveHorCursor(false);

    }

    public void MoveCursorRight(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started) MoveHorCursor(true);
    }

    private void MoveHorCursor(bool isMoveRight)
    {
        if (_cursor == FuncType.Skill)
        {
            if (isMoveRight) _horCursor = _horCursor == 3 ? 0 : _horCursor + 1;
            else _horCursor = _horCursor == 0 ? 3 : _horCursor - 1;
        }
    }
    #endregion
    #region Rsc section
    private void UpdRsc()
    {
        _rscCnt.text = RestingRsc.ToString();
    }

    private bool IsAbleToUseRsc(FuncType ft)
    {
        switch (ft)
        {
            case FuncType.HP:
                return CurMaxHPBuffer < _PM.MaxHP && RestingRsc >= _PM.HPUpgCost;
            case FuncType.SP:
                return CurSPSlotBuffer < _PM.MaxSPSlot && RestingRsc >= _PM.SPUpgCost;
            case FuncType.MP:
                return CurMPSlotBuffer < _PM.MaxMPSlot && RestingRsc >= _PM.HPUpgCost;
            default:
                return false;
        }
    }

    private bool IsAbleToReturnRsc(FuncType ft)
    {
        switch (ft)
        {
            case FuncType.HP:
                return CurMaxHPBuffer > 0;
            case FuncType.SP:
                return CurSPSlotBuffer > 0;
            case FuncType.MP:
                return CurMPSlotBuffer > 0;
            default:
                return false;
        }
    }
    #endregion

    private void UpdProp(FuncType ft)
    {
        switch (ft)
        {
            case FuncType.HP:
                for (int i = 0; i < CurMaxHPBuffer; i++) _HPs[i].enabled = true;
                for (int i = CurMaxHPBuffer; i < _PM.MaxHP; i++) _HPs[i].enabled = false;
                break;
            case FuncType.SP:
                for (int i = 0; i < CurSPSlotBuffer; i++) _SPs[i].enabled = true;
                for (int i = CurSPSlotBuffer; i < _PM.MaxSPSlot; i++) _SPs[i].enabled = false;
                break;
            case FuncType.MP:
                for (int i = 0; i < CurMPSlotBuffer; i++) _MPs[i].enabled = true;
                for (int i = CurMPSlotBuffer; i < _PM.MaxMPSlot; i++) _MPs[i].enabled = false;
                break;
            default:
                break;
        }
    }

    private void UpdSkill()
    {
        for (int i = 0; i < 4; i++)
        {
            if (IsLoaded[i])
            {
                _skills[i].enabled = true;
                for (int j = 0; j < _PM.SkillCosts[i]; j++) _skillCostFrame[i][j].enabled = true;//dspl cost frame
                for (int j = _PM.SkillCosts[i]; j < _PM.MaxSkillCost; j++) _skillCostFrame[i][j].enabled = false;

                if (IsEvled[i])//dspl cost content
                {
                    for (int j = 0; j < _PM.SkillCosts[i]; j++) _skillCostContent[i][j].enabled = true;
                    for (int j = _PM.SkillCosts[i]; j < _PM.MaxSkillCost; j++) _skillCostContent[i][j].enabled = false;
                }
                else
                {
                    for (int j = 0; j < _PM.MaxSkillCost; j++) _skillCostContent[i][j].enabled = false;
                }
            }
            else
            {
                _skills[i].enabled = false;
                for (int j = 0; j < _PM.MaxSkillCost; j++)
                {
                    _skillCostFrame[i][j].enabled = false;
                    _skillCostContent[i][j].enabled = false;
                }
            }
        }
    }

    private void ContinuouslyIpt()
    {
        if (_isUpg && (IptTimer++ >= _iptDur)) Upg(_cursor);
        if (_isDwg && (IptTimer++ >= _iptDur)) Dwg(_cursor);
    }

    #region Upg
    public void Upg(InputAction.CallbackContext context)
    {
        IptTimer = 0;//ini state
        _isUpg = context.phase != InputActionPhase.Canceled;
        if (context.phase == InputActionPhase.Started)
        {
            _isDwg = false;
            switch (_cursor)
            {
                case FuncType.Skill:
                    if (IsLoaded[_horCursor])
                    {
                        if ((!IsEvled[_horCursor]) && RestingRsc >= _PM.SkillCosts[_horCursor])//is able to upg
                        {
                            IsEvled[_horCursor] = true;
                            RestingRsc -= _PM.SkillCosts[_horCursor];
                            UpdRsc();
                            UpdSkill();
                        }
                    }
                    else if (!IsLoaded[_horCursor])//not loaded skill, ready to be loaded
                    {
                        IsLoaded[_horCursor] = true;
                        UpdSkill();
                    }
                    break;
                default:
                    Upg(_cursor);
                    break;
            }
        }
    }

    private void Upg(FuncType ft)
    {
        if (IsAbleToUseRsc(ft))
        {
            switch (ft)
            {
                case FuncType.HP:
                    CurMaxHPBuffer++;
                    RestingRsc -= _PM.HPUpgCost;
                    break;
                case FuncType.SP:
                    CurSPSlotBuffer++;
                    RestingRsc -= _PM.SPUpgCost;
                    break;
                case FuncType.MP:
                    CurMPSlotBuffer++;
                    RestingRsc -= _PM.MPUpgCost;
                    break;
                default:
                    return;
            }
            UpdProp(ft);
            UpdRsc();
            IptTimer = 0;
        }
    }
    #endregion
    #region Dwg
    public void Dwg(InputAction.CallbackContext context)
    {
        IptTimer = 0;//ini state
        _isDwg = context.phase != InputActionPhase.Canceled;
        if (context.phase == InputActionPhase.Started)
        {
            _isUpg = false;
            switch (_cursor)
            {
                case FuncType.Skill:
                    if (IsLoaded[_horCursor])
                    {
                        if (IsEvled[_horCursor])
                        {
                            IsEvled[_horCursor] = false;
                            RestingRsc += _PM.SkillCosts[_horCursor];
                            UpdRsc();
                            UpdSkill();
                        }
                        else if (IsLoaded[_horCursor])//not evled skill, ready to be unloaded
                        {
                            IsLoaded[_horCursor] = false;
                            UpdSkill();
                        }
                    }
                    break;
                default:
                    Dwg(_cursor);
                    break;
            }
        }
    }

    private void Dwg(FuncType ft)
    {
        if (IsAbleToReturnRsc(ft))
        {
            switch (ft)
            {
                case FuncType.HP:
                    CurMaxHPBuffer--;
                    RestingRsc += _PM.HPUpgCost;
                    break;
                case FuncType.SP:
                    CurSPSlotBuffer--;
                    RestingRsc += _PM.SPUpgCost;
                    break;
                case FuncType.MP:
                    CurMPSlotBuffer--;
                    RestingRsc += _PM.MPUpgCost;
                    break;
                default:
                    return;
            }
            UpdProp(ft);
            UpdRsc();
            IptTimer = 0;
        }
    }
    #endregion
}
